﻿using System;
using System.Collections.Generic;
using Sherwood.Content.DO.Model;
using Xtensive.Storage;
using System.Linq;
using Record = Sherwood.Content.DO.Model.Record;

namespace Sherwood.Content.DO.Services
{
    public class MetaRepository : IMetaRepository
    {
        /// <inheritdoc/>
        public IMeta this[Guid id]
        {
            get { return Query.All<Meta>().FirstOrDefault(m => m.Id == id); }
        }

        /// <inheritdoc/>
        public IQueryable<IMeta> All
        {
            get { return Query.All<Meta>(); }
        }

        /// <inheritdoc/>
        public IQueryable<IMeta> GetMetas(Guid recordId)
        {
            return Query.All<Meta>().Where(m => m.Record.Id == recordId);
        }

        /// <inheritdoc/>
        public IQueryable<IMeta> GetMetas(Guid recordId, string clientId)
        {
            return Query.All<Meta>().Where(m => m.Record.Id == recordId && m.Client.Id == clientId);
        }

        /// <inheritdoc/>
        public T GetMeta<T>(Guid recordId, string clientId, string usageKey) where T : IMeta
        {
            return Query.All<Meta>().OfType<T>().SingleOrDefault(m => m.Record.Id == recordId &&
                                                                      m.Client.Id == clientId &&
                                                                      m.UsageKey == usageKey);
        }

        public T CreateNew<T>(Guid recordId, string clientId, string usageKey) where T : IMeta, new()
        {
            return CreateNew<T>(Query.All<Record>().First(r => r.Id == recordId),
                                Query.All<Client>().First(c => c.Id == clientId), usageKey);
        }

        public T CreateNew<T>(IRecord record, IClient client, string usageKey) where T : IMeta, new()
        {
            var old = Meta.Instantiation;
            Meta.Instantiation = new MetaInstantiationContext((Record) record, (Client) client, usageKey);
            try
            {
                return new T();
            }
            finally
            {
                Meta.Instantiation = old;
            }
        }

        public void Delete(IMeta meta)
        {
            ((Meta)meta).Remove();
        }
    }
}